#include "RDPTB.h"

#define PRINT_TOKEN //printf ("%d '%lg'\n", s->type, s->value);

int Get_G4 (token_t* str, root_t* tree)
{
    ASSERT (str);
    TREE_CHECK (tree);

    printf ("Get_G4.\n");

    s = str;

    Get_E_G4 (tree, tree->root);

    TREE_CHECK (tree);

    GRAM_ASSERT (s->type == EOF_TYPE);

    return 0;
}

int Get_E_G4 (root_t* tree, tree_t* node)
{
    printf ("Get_E_G4.\n");
    PRINT_TOKEN;

    ASSERT (tree); ASSERT (node);

    TREE_CHECK (tree);
    NODE_CHECK (node);

    Get_T_G4 (tree, node);
    PRINT_TOKEN;

    while (s->type == OPERATION &&
          (s->value == ADD || s->value == SUB))
    {
        NODE_CHECK (node);

        int op = s->value;

        s++;

        tree_t* new_node = NULL, * new_node_2 = NULL;
        tree_t* copy_node = NULL;

        Node_Construct (&new_node, 0);
        Node_Construct (&new_node_2, 0);

        Node_Construct (&copy_node, 0);

        Node_Copy (copy_node, node);

        Node_Add_Left (tree, new_node, copy_node);

        Node_Add_Right (tree, new_node, new_node_2);

        TREE_CHECK (tree);

        Get_T_G4 (tree, new_node_2);

        new_node->info = op;
        new_node->type = OPERATION;

        Node_Copy (node, new_node);
    }

    printf ("/Get_E_G4.\n");

    return 0;
}

int Get_T_G4 (root_t* tree, tree_t* node)
{
    printf ("Get_T_G4.\n");
    PRINT_TOKEN;

    ASSERT (tree); ASSERT (node);

    TREE_CHECK (tree);
    NODE_CHECK (node);

    Get_P_G4 (tree, node);
    PRINT_TOKEN;

    while (s->type == OPERATION &&
          (s->value == MUL || s->value == DIV))
    {
        NODE_CHECK (node);

        int op = s->value;

        s++;

        tree_t* new_node = NULL, * new_node_2 = NULL;
        tree_t* copy_node = NULL;

        Node_Construct (&new_node, 0);
        Node_Construct (&new_node_2, 0);

        Node_Construct (&copy_node, 0);

        Node_Copy (copy_node, node);

        Node_Add_Left (tree, new_node, copy_node);

        Node_Add_Right (tree, new_node, new_node_2);

        TREE_CHECK (tree);

        Get_T_G4 (tree, new_node_2);

        new_node->info = op;
        new_node->type = OPERATION;

        Node_Copy (node, new_node);
    }

    printf ("/Get_T_G4.\n");

    return 0;
}

int Get_P_G4 (root_t* tree, tree_t* node)
{
    printf ("Get_P_G4.\n");
    PRINT_TOKEN;

    ASSERT (tree); ASSERT (node);

    TREE_CHECK (tree);
    NODE_CHECK (node);

    tree_t* new_node = NULL, * new_node_2 = NULL;

    Node_Construct (&new_node, 0);

    NODE_CHECK (new_node);

    node->type = OPERATION;
    node->right = NULL;
    node->left = NULL;

    Node_Add_Left (tree, node, new_node);

    if (s->value == '-')
    {
        node->info = SUB;

        s++;
    }
    else
    {
        if (s->value == '+')
        {
            s++;
        }

        node->info = ADD;
    }

    switch (s->type)
    {
        case VARIABLE:
            new_node->info = s->value;
            new_node->left = NULL;
            new_node->right = NULL;
            new_node->type = s->type;

            s++;
            break;

        case DIFF_TYPE:
            s++;

            ASSERT (s->value == L_BR);

            s++;

            Node_Construct (&new_node_2, 0);

            Node_Add_Left (tree, new_node, new_node_2);

            new_node->right = NULL;
            new_node->type = DIFF_TYPE;
            new_node->info = DIFF;

            Get_E_G4 (tree, new_node_2);

            ASSERT (s->value == R_BR);

            s++;

            break;

        case BRACKET:
            s++;

            Get_E_G4 (tree, new_node);

            GRAM_ASSERT (s->value == R_BR);

            s++;
            break;

        default:
            Get_N_G4(tree, new_node);
            break;
    }

    TREE_CHECK (tree);
    NODE_CHECK (node);
    NODE_CHECK (new_node);

    printf ("/Get_P_G4.\n");

    return 0;
}

int Get_N_G4 (root_t* tree, tree_t* node)
{
    printf ("Get_N_G4.\n");
    PRINT_TOKEN;

    ASSERT (tree); ASSERT (node);

    TREE_CHECK (tree);
    NODE_CHECK (node);

    double val = 0;

    if (s->type != NUMBER)
    {
        val = -1;

        return val;
    }

    node->info = s->value;
    node->left = NULL;
    node->right = NULL;
    node->type = NUMBER;

    s++;

    PRINT_TOKEN;

    printf ("/Get_N_G4.\n");

    return 0;
}

#undef PRINT_TOKEN
